#include "Key.h"

// 按键硬件配置结构体（集中管理硬件信息，便于扩展）
typedef struct {
    GPIO_TypeDef* port;       // 引脚所在端口
    uint16_t      pin;        // 引脚编号
    //GPIOMode_TypeDef mode;    // 输入模式（上拉/下拉）//暂时不需要(在标准库要自己定义引脚)
    uint8_t       press_level;// 按下时的电平（0/1）
} Key_HwConfig;

// 按键运行时状态结构体（封装状态变量）
typedef struct {
    uint8_t  curr_state;      // 当前电平状态（按下/未按下）
    uint8_t  prev_state;      // 上一周期电平状态
    uint8_t  state;           // 状态机状态
    uint16_t timer;           // 状态计时
} Key_RunStatus;

// 按键硬件配置表（添加新按键只需在此处扩展）
static const Key_HwConfig key_hw[] = {
    {GPIOB, GPIO_PIN_12, 1},   // KEY_1：下拉输入，按下为高电平
	{GPIOB, GPIO_PIN_15, 1}   // KEY_1：下拉输入，按下为高电平
};

// 按键状态标志（外部通过Key_Check获取）
static uint8_t key_flags[KEY_COUNT] = {0};
// 按键运行时状态数组
static Key_RunStatus key_status[KEY_COUNT] = {0};
// 扫描周期计数器
static uint8_t scan_counter = 0;


///**
// * @brief 按键初始化（配置GPIO）
// */
//void Key_Init(void)
//{
//	//根据需求添加
//}


/**
 * @brief 读取按键原始电平状态
 * @param id 按键ID
 * @return 1-按下，0-未按下
 */
static uint8_t Key_GetRawState(Key_Id id)
{
    if (id >= KEY_COUNT) return 0;	//超出退出
    
    uint8_t level = HAL_GPIO_ReadPin(key_hw[id].port, key_hw[id].pin);	//这是HAL库，标准库记得换
    return (level == key_hw[id].press_level) ? 1 : 0;
}

/**
 * @brief 检查按键状态标志
 * @param id 按键ID
 * @param flag 要检查的标志（Key_Flag）
 * @return 1-标志有效，0-标志无效
 */
uint8_t Key_Check(Key_Id id, Key_Flag flag)
{
	if (id >= KEY_COUNT) return 0;

	uint8_t result = (key_flags[id] & flag) ? 1 : 0;
	// 非HOLD标志触发后清除（HOLD需要持续保持）
	if (result && (flag != KEY_HOLD))	//（result &&）可以不要，这里双重判断提高严谨性
	{
		key_flags[id] &= ~flag;
	}
	return result;
}

/**
 * @brief 按键状态机处理（建议由定时器中断调用，1ms一次）
 */
void Key_Tick(void)
{
	 // 1. 计时处理（每个按键的定时器递减）
    for (Key_Id id = (Key_Id)0; id < KEY_COUNT; id++)		//(Key_Id)加这个告诉编译器 “类型混合是故意的”，从而消除警告，当按键个数匹配时就不会警告可以删除
	{
        if (key_status[id].timer > 0)
		{
            key_status[id].timer--;
        }
    }
	
	 // 2. 按扫描周期处理状态（默认20ms一次）
    scan_counter++;
    if (scan_counter < KEY_SCAN_INTERVAL)
	{
        return;
    }
    scan_counter = 0;
    
    // 3. 逐个处理按键状态机
    for (Key_Id id = (Key_Id)0; id < KEY_COUNT; id++)		//这里和上面一样，（Key_Id id = KEY_1;）或（Key_Id id = 0;）两种写法都可以，如果换了名字这两个地方都要改
	{
        // 更新当前/上一状态
        key_status[id].prev_state = key_status[id].curr_state;
        key_status[id].curr_state = Key_GetRawState(id);
        
        // 处理HOLD标志（持续按下时为1）
        if (key_status[id].curr_state) {
            key_flags[id] |= KEY_HOLD;
        } else {
            key_flags[id] &= ~KEY_HOLD;
        }
        
        // 处理按下边沿（DOWN）
        if (key_status[id].curr_state && !key_status[id].prev_state) {
            key_flags[id] |= KEY_DOWN;
        }
        
        // 处理释放边沿（UP）
        if (!key_status[id].curr_state && key_status[id].prev_state) {
            key_flags[id] |= KEY_UP;
        }
        
        // 状态机处理（单击/双击/长按/重复触发）
        switch (key_status[id].state) {
            case 0:  // 初始状态：等待按下
                if (key_status[id].curr_state) {
                    key_status[id].timer = KEY_TIME_LONG;  // 启动长按计时
                    key_status[id].state = 1;
                }
                break;
                
            case 1:  // 已按下：等待释放或长按
                if (!key_status[id].curr_state) {
                    // 未达到长按时间就释放，进入双击检测
                    key_status[id].timer = KEY_TIME_DOUBLE;
                    key_status[id].state = 2;
                } else if (key_status[id].timer == 0) {
                    // 达到长按时间，触发长按并进入重复状态
                    key_flags[id] |= KEY_LONG;
                    key_status[id].timer = KEY_TIME_REPEAT;
                    key_status[id].state = 4;
                }
                break;
                
            case 2:  // 释放后：等待双击或确认单击
                if (key_status[id].curr_state) {
                    // 双击触发
                    key_flags[id] |= KEY_DOUBLE;
                    key_status[id].state = 3;  // 等待第二次释放
                } else if (key_status[id].timer == 0) {
                    // 双击超时，确认单击
                    key_flags[id] |= KEY_SINGLE;
                    key_status[id].state = 0;
                }
                break;
                
            case 3:  // 双击后：等待释放
                if (!key_status[id].curr_state) {
                    key_status[id].state = 0;
                }
                break;
                
            case 4:  // 长按重复：持续触发
                if (!key_status[id].curr_state) {
                    // 释放后退出重复状态
                    key_status[id].state = 0;
                } else if (key_status[id].timer == 0) {
                    // 重复触发间隔到
                    key_flags[id] |= KEY_REPEAT;
                    key_status[id].timer = KEY_TIME_REPEAT;
                }
                break;
        }
    }
}
